#include "CloudDiskGateway.h"
#include "Logger.h"
#include "CryptoUtil.h"
#include "MessageQueue.h"
#include "ParseUtil.h"
#include "SignUp.pb.h"
#include "SignUpService.h"
#include "SignInService.h"
#include "SignIn.pb.h"
#include "UserInfoService.h"
#include "UserInfo.pb.h"
#include "FilelistQueryService.h"
#include "FilelistQuery.pb.h"
#include "Upload.pb.h"
#include "UploadService.h"
#include "ConsulCenter.h"

#include <nlohmann/json.hpp>
#include <workflow/MySQLResult.h>

#include <map>
#include <string>
#include <vector>
#include <utility>
#include <fstream>
#include <functional>

using namespace wfrest;
using namespace protocol;
using namespace srpc;
using JSON = nlohmann::json;
using std::map;
using std::string;
using std::vector;
using std::ofstream;

namespace
{
    using namespace l;
    //mysql的url
    constexpr const char* MYSQL_URL = "mysql://root:123@127.0.0.1/CloudDisk2";
    //保存前端上传文件的路径
    constexpr const char* DEFAULT_FILE_SAVE_PATH = "./resources/";
    //oss对象的基本路径名
    constexpr const char* DEFAULT_FILE_OSS_BACKUP_PATH = "resources/";
    //注册服务的端口
    constexpr const unsigned short DEFAULT_SIGNUP_PORT = 1234;
    //登录服务的端口
    constexpr const unsigned short DEFAULT_SIGNIN_PORT = 1235;
    //获取user信息的端口
    constexpr const unsigned short DEFAULT_INFO_PORT = 1236;
    //获取文件列表的端口
    constexpr const unsigned short DEFAULT_QUERY_PORT = 1237;
    //上传服务的端口
    constexpr const unsigned short DEFAULT_UPLOAD_PORT = 1238;
    //注册服务的ip
    constexpr const char* DEFAULT_SIGNUP_IP = "127.0.0.1";
    //登录服务的ip
    constexpr const char* DEFAULT_SIGNIN_IP = "127.0.0.1";
    //获取user信息的ip
    constexpr const char* DEFAULT_INFO_IP = "127.0.0.1";
    //获取文件列表的ip
    constexpr const char* DEFAULT_QUERY_IP = "127.0.0.1";
    //上传服务的ip
    constexpr const char* DEFAULT_UPLOAD_IP = "127.0.0.1";

    //默认的注册中心url
    constexpr const char* DEFAULT_CONSUL_URL = "http://192.168.56.129:8500/v1/health/service/";
    //默认的注册服务的服务名
    constexpr const char* DEFAULT_CONSUL_SIGNUP_SERVICE_NAME = "SignUp";
    //默认的登录服务的服务名
    constexpr const char* DEFAULT_CONSUL_SIGNIN_SERVICE_NAME = "SignIn";
    //默认的获取用户信息服务的服务名
    constexpr const char* DEFAULT_CONSUL_USERINFO_SERVICE_NAME = "UserInfo";
    //默认的获取文件列表服务的服务名
    constexpr const char* DEFAULT_CONSUL_FILELISTQUERY_SERVICE_NAME = "FilelistQuery";
    //默认的上传服务的服务名
    constexpr const char* DEFAULT_CONSUL_UPLOAD_SERVICE_NAME = "Upload";

    /* ************************************************************************************ */
    /* *******************************验证登录************************************************* */
    /* ************************************************************************************ */
    bool verify_login(const HttpReq* req, string& username, string& token) {

        if (!ParseUtil::parse_query_by_key(req, username, token, "username", "token")) {
            return false;
        }

#ifdef BUG
        std::cout << "username: " << username << "\n";
        std::cout << "token: " << token << "\n";
#endif

        //此处可以对username和token检错提早返回
        bool is_login = l::CryptoUtil::verify_jwt(token.c_str());
        if (username.empty() || token.empty() || !is_login) {

            return false;
        }

        return true;
    }

    /* ************************************************************************************ */
   /* *******************************获取ip和端口******************************************* */
   /* ************************************************************************************ */

    bool get_address_and_port(const string& service_name, string& address, unsigned short& port) {

        //从注册中心获取一个正常的服务
        string url{ DEFAULT_CONSUL_URL };
        ConsulCenter::splice_url(url, service_name);
#ifdef BUG
        std::cout << service_name << " consul url:" << url << "\n";
#endif

        if (!ConsulCenter::get_address_and_port(url, address, port)) {

            return false;
        }

        return true;
    }


    /* ************************************************************************************ */
    /* *******************************注册************************************************* */
    /* ************************************************************************************ */

    void handleSignup(const HttpReq* req, HttpResp* resp) {

        //解析urlencpded格式的表单body，得到userName和passWord
        string username{};
        string password{};
        if (!ParseUtil::parse_body_on_form_kv(req, username, password, "username", "password")) {
            resp->set_status(HttpStatusBadRequest);
            return;
        }
#ifdef BUG
        std::cout << "username: " << username << "\n";
        std::cout << "password: " << password << "\n";
#endif


        //从注册中心获取一个正常的服务
        string address{};
        unsigned short port;
        if (!get_address_and_port(DEFAULT_CONSUL_SIGNUP_SERVICE_NAME, address, port)) {
            resp->set_status(HttpStatusInternalServerError);
            return;
        }

#ifdef BUG
        std::cout << "ip:" << address << "\n";
        std::cout << "port:" << port << "\n";
#endif
        //打包给SignUPServer
        ::l::SignUp::SRPCClient client(address.c_str(), port);


        ::l::SignUpRequest signup_req;
        signup_req.set_username(std::move(username));
        signup_req.set_password(std::move(password));

        SignUpResponse signup_resp;
        RPCSyncContext context;
        client.SignUp(&signup_req, &signup_resp, &context);

        //判断服务是否执行成功
        if (!context.success) {

            resp->set_status(HttpStatusInternalServerError);

#ifdef BUG
            std::cout << "status code: " << context.status_code
                << ", error: " << context.error
                << ", errmsg: " << context.errmsg << "\n";
#endif
            return;
        }

        //通过SignUp服务的response携带的statusCode来设置响应
        int32_t status_code = signup_resp.statuscode();
#ifdef BUG
        std::cout << "signup status_code: " << status_code << "\n";
#endif
        if (status_code == HttpStatusOK) {
            resp->String("SUCCESS");
        }
        else {
            resp->set_status(status_code);
        }

    }

    /* ************************************************************************************ */
    /* *******************************登录************************************************* */
    /* ************************************************************************************ */

    void handleSignin(const HttpReq* req, HttpResp* resp) {

        //解析urlencpded格式的表单body，得到userName和passWord
        string username{};
        string password{};
        if (!ParseUtil::parse_body_on_form_kv(req, username, password, "username", "password")) {
            resp->set_status(HttpStatusBadRequest);
            return;
        }
#ifdef BUG
        std::cout << "username: " << username << "\n";
        std::cout << "password: " << password << "\n";
#endif

        //从注册中心获取一个正常的服务
        string address{};
        unsigned short port;
        if (!get_address_and_port(DEFAULT_CONSUL_SIGNIN_SERVICE_NAME, address, port)) {
            resp->set_status(HttpStatusInternalServerError);
            return;
        }

#ifdef BUG
        std::cout << "ip:" << address << "\n";
        std::cout << "port:" << port << "\n";
#endif

        //打包给SignInServer
        ::l::SignIn::SRPCClient client(address.c_str(), port);


        ::l::SignInRequest signin_req;
        signin_req.set_username(std::move(username));
        signin_req.set_password(std::move(password));

        SignInResponse signin_resp;
        RPCSyncContext context;
        client.SignIn(&signin_req, &signin_resp, &context);

        //判断服务是否执行成功
        if (!context.success) {

            resp->set_status(HttpStatusInternalServerError);

#ifdef BUG
            std::cout << "status code: " << context.status_code
                << ", error: " << context.error
                << ", errmsg: " << context.errmsg << "\n";
#endif
            return;
        }

        //通过SignIn服务的response携带的statusCode来设置响应
        int32_t status_code = signin_resp.statuscode();
#ifdef BUG
        std::cout << "login status_code: " << status_code << "\n";
#endif
        if (status_code == HttpStatusOK) {
            resp->String(signin_resp.respbody());
        }
        else {
            resp->set_status(status_code);
        }

    }

    /* ************************************************************************************ */
   /* *******************************获取用户信息******************************************* */
   /* ************************************************************************************ */

    void handleInfo(const HttpReq* req, HttpResp* resp) {

        string username{};
        string token{};
        if (!verify_login(req, username, token)) {
            resp->Redirect("/static/view/signin.html", HttpStatusSeeOther);
            LogWarn("verify login failed in get user Information");
#ifdef BUG
            std::cout << "verify login failed in get user Information" << "\n";
#endif
            return;
        }

        //从注册中心获取一个正常的服务
        string address{};
        unsigned short port;
        if (!get_address_and_port(DEFAULT_CONSUL_USERINFO_SERVICE_NAME, address, port)) {
            resp->set_status(HttpStatusInternalServerError);
            return;
        }

#ifdef BUG
        std::cout << "ip:" << address << "\n";
        std::cout << "port:" << port << "\n";
#endif


        //打包给UserInfoServer
        ::l::UserInfo::SRPCClient client(address.c_str(), port);


        ::l::UserInfoRequest userinfo_req;
        userinfo_req.set_username(std::move(username));

        UserInfoResponse userinfo_resp;
        RPCSyncContext context;
        client.UserInfo(&userinfo_req, &userinfo_resp, &context);

        //判断服务是否执行成功
        if (!context.success) {

            resp->set_status(HttpStatusInternalServerError);

#ifdef BUG
            std::cout << "status code: " << context.status_code
                << ", error: " << context.error
                << ", errmsg: " << context.errmsg << "\n";
#endif
            return;
        }

        //通过UserInfo服务的response携带的statusCode来设置响应
        int32_t status_code = userinfo_resp.statuscode();
#ifdef BUG
        std::cout << "login status_code: " << status_code << "\n";
#endif
        if (status_code == HttpStatusOK) {
            resp->String(userinfo_resp.userinfo());
        }
        else {
            resp->set_status(status_code);
        }

    }

    /* ************************************************************************************ */
  /* *******************************获取文件列表******************************************* */
  /* ************************************************************************************ */

    void handleQuery(const HttpReq* req, HttpResp* resp) {

        string username{};
        string token{};
        if (!verify_login(req, username, token)) {
            resp->Redirect("/static/view/signin.html", HttpStatusSeeOther);
            LogWarn("verify login failed in get file list");
#ifdef BUG
            std::cout << "verify login failed in get file list" << "\n";
#endif
            return;
        }

        string limit{};
        if (!ParseUtil::parse_body_on_form_kv(req, limit, "limit")) {
            resp->set_status(HttpStatusBadRequest);
            return;
        }
#ifdef BUG
        std::cout << "filelist limit: " << limit << "\n";
#endif

        //从注册中心获取一个正常的服务
        string address{};
        unsigned short port;
        if (!get_address_and_port(DEFAULT_CONSUL_FILELISTQUERY_SERVICE_NAME, address, port)) {
            resp->set_status(HttpStatusInternalServerError);
            return;
        }

#ifdef BUG
        std::cout << "ip:" << address << "\n";
        std::cout << "port:" << port << "\n";
#endif

        //打包给FilelistQueryServer
        ::l::FilelistQuery::SRPCClient client(address.c_str(), port);

        ::l::FilelistQueryRequest filelist_query_req;
        filelist_query_req.set_username(std::move(username));
        filelist_query_req.set_limit(std::move(limit));

        FilelistQueryResponse filelist_query_resp;
        RPCSyncContext context;
        client.FilelistQuery(&filelist_query_req, &filelist_query_resp, &context);

        //判断服务是否执行成功
        if (!context.success) {

            resp->set_status(HttpStatusInternalServerError);

#ifdef BUG
            std::cout << "status code: " << context.status_code
                << ", error: " << context.error
                << ", errmsg: " << context.errmsg << "\n";
#endif
            return;
        }

        //通过FilelistQuery服务的response携带的statusCode来设置响应
        int32_t status_code = filelist_query_resp.statuscode();
#ifdef BUG
        std::cout << "filelist_query status_code: " << status_code << "\n";
#endif
        if (status_code == HttpStatusOK) {
            resp->String(filelist_query_resp.filelist());
        }
        else {
            resp->set_status(status_code);
        }

    }

    /* ************************************************************************************ */
     /* ************************************上传******************************************* */
     /* ************************************************************************************ */

    void handleUpload(const HttpReq* req, HttpResp* resp) {

        //验证登录
        string username{};
        string token{};
        if (!verify_login(req, username, token)) {
            resp->Redirect("/static/view/signin.html", HttpStatusSeeOther);
#ifdef BUG
            std::cout << "verify_login failed in upload" << "\n";
#endif
            return;
        }

        if (req->content_type() != MULTIPART_FORM_DATA) {
            resp->set_status(HttpStatusBadRequest);
            return;
        }

        const Form& form = req->form();
        string filename{};
        string fileContent{};

        for (auto& [_, file] : form) {

            filename = file.first;
            fileContent = file.second;
        }

        //从注册中心获取一个正常的服务
        string address{};
        unsigned short port;
        if (!get_address_and_port(DEFAULT_CONSUL_UPLOAD_SERVICE_NAME, address, port)) {
            resp->set_status(HttpStatusInternalServerError);
            return;
        }

#ifdef BUG
        std::cout << "ip:" << address << "\n";
        std::cout << "port:" << port << "\n";
#endif

        //打包给UploadServer
        ::l::Upload::SRPCClient client(address.c_str(), port);

        ::l::UploadRequest upload_req;
        upload_req.set_username(std::move(username));
        upload_req.set_filename(std::move(filename));
        upload_req.set_filecontent(std::move(fileContent));

        UploadResponse upload_resp;
        RPCSyncContext context;
        client.Upload(&upload_req, &upload_resp, &context);

        //判断服务是否执行成功
        if (!context.success) {

            resp->set_status(HttpStatusInternalServerError);

#ifdef BUG
            std::cout << "status code: " << context.status_code
                << ", error: " << context.error
                << ", errmsg: " << context.errmsg << "\n";
#endif
            return;
        }

        //通过Upload服务的response携带的statusCode来设置响应
        int32_t status_code = upload_resp.statuscode();
#ifdef BUG
        std::cout << "upload status_code: " << status_code << "\n";
#endif
        if (status_code == HttpStatusOK) {

            //上传成功跳转到用户的首页
            resp->Redirect("/static/view/home.html", HttpStatusSeeOther);

        }
        else {
            resp->set_status(status_code);
        }

    }

    /* ************************************************************************************ */
     /* ************************************下载******************************************* */
     /* ************************************************************************************ */

    void handleDownload(const HttpReq* req, HttpResp* resp) {

        string username{};
        string token{};
        if (!verify_login(req, username, token)) {
            resp->Redirect("/static/view/signin.html", HttpStatusSeeOther);
#ifdef BUG
            std::cout << "verify login failed" << "\n";
#endif
            return;
        }

        string filename{};
        string filehash{};
        if (!ParseUtil::parse_query_by_key(req, filename, filehash, "filename", "filehash")) {
            resp->set_status(HttpStatusBadRequest);
            return;
        }

#ifdef BUG
        std::cout << "filename: " << filename << "\n";
        std::cout << "filehash: " << filehash << "\n";
        std::cout << "username: " << username << "\n";
        std::cout << "token: " << token << "\n";
#endif

        //直接返回文件数据
        string real_path{ DEFAULT_FILE_SAVE_PATH };
        real_path.append(filehash);
        resp->File(real_path);

    }

}//end of namaspace anonymous


namespace l
{

    //注册注册路由
    void CloudDiskGateway::register_signup_module() {

        m_http_server.POST("user/signup", handleSignup);

    }

    //注册登录路由
    void CloudDiskGateway::register_signin_module() {
        m_http_server.POST("user/signin", handleSignin);
    }


    //注册获取user信息路由
    void CloudDiskGateway::register_userinfo_module() {
        m_http_server.GET("user/info", handleInfo);
    }

    //注册获取文件列表路由
    void CloudDiskGateway::register_filelist_module() {
        m_http_server.POST("file/query", handleQuery);
    }

    //注册文件上传路由
    void CloudDiskGateway::register_fileupload_module() {
        m_http_server.POST("file/upload", handleUpload);
    }


    //注册文件下载路由
    void CloudDiskGateway::register_filedownload_module() {
        m_http_server.GET("file/download", handleDownload);
    }

    void CloudDiskGateway::register_modules()
    {
        // 设置静态资源的路由
        register_static_resources_module();
        register_signup_module();
        register_signin_module();
        register_userinfo_module();
        register_filelist_module();
        register_fileupload_module();
        register_filedownload_module();
    }

    void CloudDiskGateway::register_static_resources_module()
    {
        m_http_server.GET("/user/signup", [](const HttpReq*, HttpResp* resp) {
            resp->File("static/view/signup.html");
            });

        m_http_server.GET("/static/view/signin.html", [](const HttpReq*, HttpResp* resp) {
            resp->File("static/view/signin.html");
            });

        m_http_server.GET("/static/view/home.html", [](const HttpReq*, HttpResp* resp) {
            resp->File("static/view/home.html");
            });

        m_http_server.GET("/static/js/auth.js", [](const HttpReq*, HttpResp* resp) {
            resp->File("static/js/auth.js");
            });

        m_http_server.GET("/static/img/avatar.jpeg", [](const HttpReq*, HttpResp* resp) {
            resp->File("static/img/avatar.jpeg");
            });

        m_http_server.GET("/file/upload", [](const HttpReq*, HttpResp* resp) {
            resp->File("static/view/index.html");
            });

        m_http_server.Static("/file/upload_files", "static/view/upload_files");
    }

}//end os namespaca l